﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Demo_Socket_Service
{
    public class NotifyPropertyChange : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private ObservableCollection<string> _LClientItem = new ObservableCollection<string>();
        public ObservableCollection<string> LClientItem
        {
            get { return _LClientItem; }
            set { if (_LClientItem != value) { _LClientItem = value; RaisePropertyChanged(""); } }
        }
    }

    public class ViewModel
    {
        #region 建立单例

        private static ViewModel uniqueInstance;

        private static readonly object locker = new object();

        public static ViewModel GetInstance()
        {
            if (uniqueInstance == null)
            {
                lock (locker)
                {
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new ViewModel();
                    }
                }
            }
            return uniqueInstance;
        }

        #endregion

        public NotifyPropertyChange m_NotifyPropertyChange = new NotifyPropertyChange();


    }

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = ViewModel.GetInstance().m_NotifyPropertyChange;
            ViewModel.GetInstance().m_NotifyPropertyChange.LClientItem.Add("AllConnection");
            C_RemoteEndPoint.SelectedIndex = 0;
            mySocketInit();
        }

        //初始化客户端类
        private CsMySocketService mySocketService = new CsMySocketService();
        private CsMySocketService.SocketServiceIP ServiceIP;

        //初始化服务器IP和端口号+绑定消息接收事件
        private void mySocketInit()
        {
            mySocketService.ReceEvent += ReceClientDataClick;
        }

        private bool ReceTCP(string strIn)
        {
            var strCompare = strIn.Split('=');
            if (strCompare.Count() > 1)
            {
                if (strCompare[0] == "#TCP000")
                {
                    T_LocalEndPoint.Text = mySocketService.LocalEndPoint();
                    T_RemoteEndPoint.Text = strCompare[1];
                    ViewModel.GetInstance().m_NotifyPropertyChange.LClientItem.Add(strCompare[1]);
                    return false;
                }
                if (strCompare[0] == "#TCP404")
                {
                    ViewModel.GetInstance().m_NotifyPropertyChange.LClientItem.Remove(strCompare[1]);
                    T_RemoteEndPoint.Text = string.Format("{0}=已断开", strCompare[1]);
                    return false;
                }
                if (strCompare[1] == "")
                {
                    return false;
                }
            }
            return true;
        }

        private void ReceClientDataClick(string strIn)
        {
            System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate ()
            {
                if (!ReceTCP(strIn))
                    return;
                if (false)
                    TxRece.Text += strIn;
                else
                    TxRece.Text += strIn + "\r\n";
            });
        }

        private void BtTxSend_Click(object sender, RoutedEventArgs e) => mySocketService.SendData(C_RemoteEndPoint.Text, TxSend.Text);

        private void BtClearTxRece_Click(object sender, RoutedEventArgs e) => TxRece.Text = string.Empty;

        private void BtBreak_Click(object sender, RoutedEventArgs e)
        {
            mySocketService.SocketBreak(C_RemoteEndPoint.Text, ServiceIP);
            T_LocalEndPoint.Text = "主动断开";
            T_RemoteEndPoint.Text = "强迫远程断开";
        }

        private void BtConnect_Click(object sender, RoutedEventArgs e)
        {
            if (mySocketService.tcpServiceMain == null)
            {
                ServiceIP.strIpAddress = ViewIP.Text;
                ServiceIP.nPort = int.Parse(ViewPoint.Text);

                mySocketService.SocketFound(ServiceIP);
                T_LocalEndPoint.Text = mySocketService.LocalEndPoint();
                T_RemoteEndPoint.Text = "等待远程连接";
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ServiceIP.strIpAddress = ViewIP.Text;
            ServiceIP.nPort = int.Parse(ViewPoint.Text);

            mySocketService.SocketFound(ServiceIP);
            T_LocalEndPoint.Text = mySocketService.LocalEndPoint();
            T_RemoteEndPoint.Text = "等待远程连接";
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            mySocketService.SocketBreak(C_RemoteEndPoint.Text, ServiceIP);
        }
    }

    public class CsMySocketService
    {
        /// <summary>
        /// 作者:WangJunLiang || Wechat:Joronwongx
        /// </summary>
        public CsMySocketService()//需要初始化
        {
            BackgroundWorker = new BackgroundWorker();
            BackgroundWorker.DoWork += FoundClientReceClick;
            BackgroundWorker.WorkerSupportsCancellation = true; //允许取消
        }

        private static Dictionary<string, Socket> LSocketClient = new Dictionary<string, Socket>();
        private static Dictionary<string, BackgroundWorker> LBackgroundWorkerClient = new Dictionary<string, BackgroundWorker>();

        public Socket tcpServiceMain = null;
        private BackgroundWorker BackgroundWorker = null;

        public delegate void ReceClientData(string strRece);
        public event ReceClientData ReceEvent;

        public struct SocketServiceIP
        {
            public string strIpAddress;
            public int nPort;
        };

        //本地连接Point
        public string LocalEndPoint() => tcpServiceMain.LocalEndPoint.ToString();

        //创建连接
        public bool SocketFound(SocketServiceIP ServiceIP)
        {
            try
            {
                if (tcpServiceMain != null)
                    return false;
                tcpServiceMain = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                EndPoint point = new IPEndPoint(IPAddress.Parse(ServiceIP.strIpAddress), ServiceIP.nPort);

                tcpServiceMain.Bind(point);
                tcpServiceMain.Listen(100);
                BackgroundWorker.RunWorkerAsync();//开始执行DoWork
                return true;
            }
            catch (System.Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                tcpServiceMain = null;
                return false;
            }
        }

        //断开连接
        public bool SocketBreak(string strKey, SocketServiceIP ServiceIP)
        {
            try
            {
                if (tcpServiceMain != null)
                {
                    if (tcpServiceMain != null)
                    {
                        if (strKey == "AllConnection")
                        {
                            BackgroundWorker.CancelAsync();
                            //通过IP和端口号来定位一个所要连接的服务器端
                            new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp).Connect(new IPEndPoint(IPAddress.Parse(ServiceIP.strIpAddress), ServiceIP.nPort));
                            //结束子客户端线程
                            foreach (var item in LSocketClient)
                            {
                                item.Value.Shutdown(SocketShutdown.Both);
                            }
                        }
                        else
                            LSocketClient[strKey].Shutdown(SocketShutdown.Both);
                    }
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                return false;
            }
        }

        //发送内容
        public void SendData(string strKey, string strIn)
        {
            try
            {
                if (tcpServiceMain != null)
                {
                    if (strKey == "AllConnection")
                        foreach (var item in LSocketClient)
                            item.Value.Send(Encoding.UTF8.GetBytes(strIn));//将字符串转化为字节数组，然后发送到服务器端
                    else
                        LSocketClient[strKey].Send(Encoding.UTF8.GetBytes(strIn));//将字符串转化为字节数组，然后发送到服务器端
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }

        //创建子客户端消息线程
        private void FoundClientReceClick(object sender, DoWorkEventArgs e)
        {
            Socket socketItem;
            while (!BackgroundWorker.CancellationPending)
            {
                socketItem = tcpServiceMain.Accept();
                if (BackgroundWorker.CancellationPending)
                    break;
                if (socketItem != null)
                {
                    BackgroundWorker ServiceBackgroundWorker = new BackgroundWorker();
                    ServiceBackgroundWorker.DoWork += ReceClientDataClick;
                    ServiceBackgroundWorker.WorkerSupportsCancellation = true; //允许取消

                    //子客户端 ip+point
                    var strRp = socketItem.RemoteEndPoint.ToString();
                    LSocketClient.Add(strRp, socketItem);
                    LBackgroundWorkerClient.Add(strRp, ServiceBackgroundWorker);
                    ReceEvent(string.Format("#TCP000={0}", strRp));
                    ServiceBackgroundWorker.RunWorkerAsync(socketItem);//开始执行DoWork
                }
            }
            tcpServiceMain.Close();
            tcpServiceMain = null;
        }

        //内容监听 socketItem代表子客户端的id
        private void ReceClientDataClick(object sender, DoWorkEventArgs e)
        {
            Socket socketItem = (Socket)e.Argument;
            var strRp = socketItem.RemoteEndPoint.ToString();
            while (!LBackgroundWorkerClient[strRp].CancellationPending)
            {
                try
                {
                    if (socketItem.Poll(10, SelectMode.SelectRead))
                    {
                        LBackgroundWorkerClient[strRp].CancelAsync();//停止执行DoWork
                        break;
                    }
                    byte[] data = new byte[1024];  //传递一个byte数组，用于接收数据。length表示接收了多少字节的数据
                    int length = socketItem.Receive(data);
                    string strOut = Encoding.UTF8.GetString(data, 0, length);//只将接收到的数据进行转化 =========阻塞======

                    ReceEvent(string.Format("[{0}]={1}", strRp, strOut));
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    ReceEvent(string.Format("[{0}]={1}", strRp, ex.Message));
                }
            }
            ReceEvent(string.Format("#TCP404={0}", strRp));
            LSocketClient[strRp].Shutdown(SocketShutdown.Both);
            LSocketClient[strRp].Close();
            LBackgroundWorkerClient.Remove(strRp);
            LSocketClient.Remove(strRp);
        }
    }

}
